{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Variational classifier - Parity Classification\n",
    "\n",
    "This notebook is adapted from the [Pennylane tutorial](https://pennylane.ai/qml/demos/tutorial_variational_classifier.html) on variational quantum classifiers. We show how to combine Pennylane's QML facilities with Covalent to learn the parity function\n",
    "\n",
    "$$\n",
    "f: x \\in \\{0, 1\\}^n  \\to \\left\\{\\begin{array}{ll} 1, & x \\text{ contains an odd number of 1's}\\\\\n",
    "0, & x \\text{ contains an even number of 1's.}\\end{array}\\right.\n",
    "$$\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First we install the required packages."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "covalent\n",
      "matplotlib==3.4.3\n",
      "pennylane==0.25.1\n"
     ]
    }
   ],
   "source": [
    "with open(\"./requirements.txt\", \"r\") as file:\n",
    "    for line in file:\n",
    "        print(line.rstrip())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Install required packages\n",
    "# !pip install -r ./requirements.txt\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We import PennyLane, the PennyLane-provided version of NumPy, and an optimizer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pennylane as qml\n",
    "from pennylane import numpy as np\n",
    "import covalent as ct\n",
    "import matplotlib.pyplot as plt\n",
    "from pennylane.optimize import NesterovMomentumOptimizer\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "dev = qml.device(\"default.qubit\", wires=4)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Variational classifiers usually define a “layer” or “block”, which is an elementary circuit architecture that gets repeated to build the variational circuit.\n",
    "We have a quantum circuit which contains some rotation gates with trainable rotation angles. The qubits are also being entangled using circular entanglement. \n",
    "\n",
    "<p> Our quantum circuit architecture is inspired by\n",
    "<a class=\"reference external\" href=\"https://arxiv.org/abs/1802.06002\">Farhi and Neven (2018)</a> as well as\n",
    "<a class=\"reference external\" href=\"https://arxiv.org/abs/1804.00633\">Schuld et al. (2018)</a>.</p>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def layer(W):\n",
    "\n",
    "    qml.Rot(W[0, 0], W[0, 1], W[0, 2], wires=0)\n",
    "    qml.Rot(W[1, 0], W[1, 1], W[1, 2], wires=1)\n",
    "    qml.Rot(W[2, 0], W[2, 1], W[2, 2], wires=2)\n",
    "    qml.Rot(W[3, 0], W[3, 1], W[3, 2], wires=3)\n",
    "\n",
    "    qml.CNOT(wires=[0, 1])\n",
    "    qml.CNOT(wires=[1, 2])\n",
    "    qml.CNOT(wires=[2, 3])\n",
    "    qml.CNOT(wires=[3, 0])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We also need a way to encode data inputs x into the circuit, so that the measured output depends on the inputs. We use the BasisState function provided by PennyLane to encode the bit vectors into basis states as follows:\n",
    "$$\n",
    "x = 0101 \\mapsto |0101\\rangle.\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## @ct.electron\n",
    "\n",
    "Each major step of the workflow is constructed using the `ct.electron` decorator which transforms a function into an Electron object. Electrons are self-contained building blocks of a Covalent workflow. \n",
    "\n",
    "We begin by defining some (non-Electron) auxiliary functions. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def statepreparation(x):\n",
    "    qml.BasisState(x, wires=[0, 1, 2, 3])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we define the quantum node as a state preparation routine, followed by a repetition of the layer structure. Borrowing from machine learning, we call the parameters weights."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "@qml.qnode(dev)\n",
    "def circuit(weights, x):\n",
    "\n",
    "    statepreparation(x)\n",
    "\n",
    "    for W in weights:\n",
    "        layer(W)\n",
    "\n",
    "    return qml.expval(qml.PauliZ(0))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The circuit takes the input state x and then applies the quantum model. Finally it applies Z measurement and returns the result to classical training system.\n",
    "\n",
    "Here the weights are the trainable parameters which are being trained based on the cost function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def variational_classifier(weights, bias, x):\n",
    "    return circuit(weights, x) + bias\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We use a mean square loss function as a cost function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def square_loss(labels, predictions):\n",
    "    loss = 0\n",
    "    for l, p in zip(labels, predictions):\n",
    "        loss = loss + (l - p) ** 2\n",
    "\n",
    "    loss = loss / len(labels)\n",
    "    return loss\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We check for accuracy by comparing the true parity values with the prediction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def accuracy(labels, predictions):\n",
    "\n",
    "    loss = 0\n",
    "    for l, p in zip(labels, predictions):\n",
    "        if abs(l - p) < 1e-5:\n",
    "            loss = loss + 1\n",
    "    loss = loss / len(labels)\n",
    "\n",
    "    return loss\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Cost</h3>\n",
    "\n",
    "We use the standard square loss that measures the distance between target labels and model predictions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cost(weights, bias, X, Y):\n",
    "    predictions = [variational_classifier(weights, bias, x) for x in X]\n",
    "    return square_loss(Y, predictions)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Optimization</h3>\n",
    "\n",
    "We use a NesterovMomentumOptimizer to perform the training optimization. The advantage of this optimizer from using Gradient descent is that, it a minimum loss path has been found, it uses the momentum to speed up the learning process.\n",
    "\n",
    "<p>The parity dataset can be downloaded\n",
    "<span class=\"html\"><a href=\"https://raw.githubusercontent.com/XanaduAI/qml/master/demonstrations/variational_classifier/data/parity.txt\" download=\"parity.txt\" target=\"_blank\">here</a></span> and\n",
    "should be placed in the subfolder <code class=\"docutils literal notranslate\"><span class=\"pre\">./assets/parity.txt</span></code>.</p>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "@ct.electron\n",
    "def get_optimizer():\n",
    "    return NesterovMomentumOptimizer(0.25)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We initialize the variables randomly (but fix a seed for reproducibility). The first variable in the list is used as a bias, while the rest is fed into the gates of the variational circuit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "@ct.electron(executor=\"local\")\n",
    "def weights_bias_init(num_layers, num_qubits):\n",
    "    weights_init = 0.01 * np.random.randn(num_layers, num_qubits, 3, requires_grad=True)\n",
    "    bias_init = np.array(0.0, requires_grad=True)\n",
    "    return weights_init, bias_init\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note**: The \"local\" executor is used for this Electron to work around a serialization bug in the default Dask-based executor. This issue will be addressed in a later release."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now perform the training for 25 iterations with a batch size of 5. The model's output is converted to -1 if it's 0 and +1 if it's 1 so as to match the dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "@ct.electron\n",
    "def training(opt, weights, bias, epochs, batch_size, X, Y, num_layers, num_qubits, cost):\n",
    "    # weights,bias = weights_bias_init(num_layers,num_qubits)\n",
    "    training_steps = []\n",
    "    cost_steps = []\n",
    "    accuracy_steps = []\n",
    "    for it in range(epochs):\n",
    "        batch_index = np.random.randint(0, len(X), (batch_size,))\n",
    "        X_batch = X[batch_index]\n",
    "        Y_batch = Y[batch_index]\n",
    "        weights, bias, _, _ = opt.step(cost, weights, bias, X_batch, Y_batch)\n",
    "\n",
    "        # Compute accuracy\n",
    "        predictions = [np.sign(variational_classifier(weights, bias, x)) for x in X]\n",
    "        acc = accuracy(Y, predictions)\n",
    "        training_steps.append(it)\n",
    "        cost_steps.append(cost(weights, bias, X, Y))\n",
    "        accuracy_steps.append(acc)\n",
    "\n",
    "        print(\n",
    "            \"Iter: {:5d} | Cost: {:0.7f} | Accuracy: {:0.7f} \".format(\n",
    "                it + 1, cost(weights, bias, X, Y), acc\n",
    "            )\n",
    "        )\n",
    "\n",
    "    return weights, bias, training_steps, cost_steps, accuracy_steps\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We create a workflow using covalent and distribute the loads"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3> @ct.lattice </h3>\n",
    "\n",
    "We now construct a Lattice tying together the different Electrons comprising the workflow."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "@ct.lattice\n",
    "def workflow(epochs, num_layers, num_qubits, X, Y):\n",
    "    opt = get_optimizer()\n",
    "    weights, bias = weights_bias_init(num_layers, num_qubits)\n",
    "    batch_size = 5\n",
    "    weights, bias, training_steps, cost_steps, accuracy_steps = training(\n",
    "        opt, weights, bias, epochs, batch_size, X, Y, num_layers, num_qubits, cost\n",
    "    )\n",
    "    return weights, bias, training_steps, cost_steps, accuracy_steps\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X = [0. 0. 0. 0.], Y = -1\n",
      "X = [0. 0. 0. 1.], Y =  1\n",
      "X = [0. 0. 1. 0.], Y =  1\n",
      "X = [0. 0. 1. 1.], Y = -1\n",
      "X = [0. 1. 0. 0.], Y =  1\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "data = np.loadtxt(\"assets/parity.txt\")\n",
    "X = np.array(data[:, :-1], requires_grad=False)\n",
    "Y = np.array(data[:, -1], requires_grad=False)\n",
    "Y = Y * 2 - np.ones(len(Y))  # shift label from {0, 1} to {-1, 1}\n",
    "\n",
    "for i in range(5):\n",
    "    print(\"X = {}, Y = {: d}\".format(X[i], int(Y[i])))\n",
    "\n",
    "print(\"...\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We dispatch the workflow. The results are obtained from the covalent and plotted:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "dispatch_id = ct.dispatch(workflow)(X=X, Y=Y, epochs=25, num_layers=2, num_qubits=4)\n",
    "result = ct.get_result(dispatch_id=dispatch_id, wait=True)\n",
    "weights, bias, training_steps, cost_steps, accuracy_steps = result.result\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(training_steps, accuracy_steps)\n",
    "plt.xlabel(\"Step\")\n",
    "plt.ylabel(\"Accuracy\")\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3> References </h3>\n",
    "\n",
    "<UL>\n",
    "    <LI>https://pennylane.ai/qml/demos/tutorial_variational_classifier.html</LI>\n",
    "    <LI>https://covalent.readthedocs.io/en/latest/index.html</LI>\n",
    "</UL>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "new",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  },
  "vscode": {
   "interpreter": {
    "hash": "65f23ff11413a1b24e6045f226bbb649c5d31fd62a4c12b34b399c99ac705181"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
